//
//  EXQueryOptimizer.m
//  ORM
//
//  Created by PH on 23.12.09.
//  Copyright 2009-2010 Codesign. All rights reserved.
//

#import "EXQueryOptimizer.h"

@implementation EXQueryOptimizer

- (id)initWithQuery:(EXQuery*)_query {
	if ((self = [super init])) {
		query = [_query retain];
	}
	return self;
}

- (void(^)(void*))conditionalBlockWithKVStore:(NSObject<ORMKeyValueStore>*)KVStore {
	return [self inspectPredicate: [query predicate] KVStore: KVStore];
}

- (id)inspectExpression:(NSExpression*)expression KVStore:(NSObject<ORMKeyValueStore>*)KVStore {
	if ([expression expressionType] == NSConstantValueExpressionType) {
		return [expression constantValue];
	} else if ([expression expressionType] == NSKeyPathExpressionType) {
		NSString* keyPath = [expression keyPath];
		NSArray* comps = [keyPath componentsSeparatedByString: @"."];
		if ([comps count] == 1) return [[query localVars] objectForKey: keyPath];
		else return comps;
	} else NSLog(@"Unknown expression type");
	return nil;
}

- (void(^)(void*))inspectPredicate:(id)predicate KVStore:(NSObject<ORMKeyValueStore>*)KVStore {
	if ([predicate isKindOfClass: [NSCompoundPredicate class]]) {
		/*if ([predicate compoundPredicateType] == NSNotPredicateType) {
			[code appendString: @"(NOT "];
			[self inspectPredicate: [[predicate subpredicates] objectAtIndex: 0] code: code arguments: arguments];
			[code appendString: @")"];
			return YES;
		} else*/ if ([predicate compoundPredicateType] == NSAndPredicateType) {
			NSArray* subpredicates = [predicate subpredicates];
			NSMutableArray* condBlocks = [NSMutableArray arrayWithCapacity: [subpredicates count]];
			for (int i = 0; i < [subpredicates count]; i++) {
				NSPredicate* subpredicate = [subpredicates objectAtIndex: i];
				void(^condBlock)(void*) = [self inspectPredicate: subpredicate KVStore: KVStore];
				if (condBlock == nil) return nil;
				[condBlocks addObject: condBlock];
			}
			return [[^void(void* qry) {
				for (void(^condBlock)(void*) in condBlocks) {
					condBlock(qry);
				}
			} copy] autorelease];
		/*} else if ([predicate compoundPredicateType] == NSOrPredicateType) {
			[code appendString: @"("];
			NSArray* subpredicates = [predicate subpredicates];
			for (int i = 0; i < [subpredicates count]; i++) {
				if (i > 0) [code appendString: @" OR "];
				NSPredicate* subpredicate = [subpredicates objectAtIndex: i];
				[self inspectPredicate: subpredicate code: code arguments: arguments];
			}
			[code appendString: @")"];
			return YES;*/
		} else NSLog(@"Unknown compound type");
	} else if ([predicate isKindOfClass: [NSComparisonPredicate class]]) {
		if ([predicate predicateOperatorType] == NSEqualToPredicateOperatorType
			&& [predicate comparisonPredicateModifier] == NSDirectPredicateModifier
			&& [predicate options] == 0) {
			id leftParam = [self inspectExpression: [predicate leftExpression] KVStore: KVStore];
			if (leftParam == nil) return nil;
			id rightParam = [self inspectExpression: [predicate rightExpression] KVStore: KVStore];
			if (rightParam == nil) return nil;
			if ([leftParam isKindOfClass: [NSArray class]])
				return [KVStore stringEqualConditionWithColumnName: [NSString stringWithFormat: @"field_%@", [leftParam objectAtIndex: 1]] value: rightParam];
			else return [KVStore stringEqualConditionWithColumnName: [NSString stringWithFormat: @"field_%@", [rightParam objectAtIndex: 1]] value: leftParam];
		/*} else if ([predicate predicateOperatorType] == NSNotEqualToPredicateOperatorType
				   && [predicate comparisonPredicateModifier] == NSDirectPredicateModifier
				   && [predicate options] == 0) {
			if ([self inspectExpression: [predicate leftExpression] code: code arguments: arguments] == NO) return NO;
			[code appendString: @" <> "];
			if ([self inspectExpression: [predicate rightExpression] code: code arguments: arguments] == NO) return NO;
			return YES;
		} else if ([predicate predicateOperatorType] == NSLikePredicateOperatorType
				   && [predicate comparisonPredicateModifier] == NSDirectPredicateModifier
				   && [predicate options] == 0) {
			if ([self inspectExpression: [predicate leftExpression] code: code arguments: arguments] == NO) return NO;
			[code appendString: @" LIKE "];
			if ([self inspectExpression: [predicate rightExpression] code: code arguments: arguments] == NO) return NO;
			return YES;
		} else if ([predicate predicateOperatorType] == NSLessThanPredicateOperatorType
				   && [predicate comparisonPredicateModifier] == NSDirectPredicateModifier
				   && [predicate options] == 0) {
			if ([self inspectExpression: [predicate leftExpression] code: code arguments: arguments] == NO) return NO;
			[code appendString: @" < "];
			if ([self inspectExpression: [predicate rightExpression] code: code arguments: arguments] == NO) return NO;
			return YES;
		} else if ([predicate predicateOperatorType] == NSLessThanOrEqualToPredicateOperatorType
				   && [predicate comparisonPredicateModifier] == NSDirectPredicateModifier
				   && [predicate options] == 0) {
			if ([self inspectExpression: [predicate leftExpression] code: code arguments: arguments] == NO) return NO;
			[code appendString: @" <= "];
			if ([self inspectExpression: [predicate rightExpression] code: code arguments: arguments] == NO) return NO;
			return YES;
		} else if ([predicate predicateOperatorType] == NSGreaterThanPredicateOperatorType
				   && [predicate comparisonPredicateModifier] == NSDirectPredicateModifier
				   && [predicate options] == 0) {
			if ([self inspectExpression: [predicate leftExpression] code: code arguments: arguments] == NO) return NO;
			[code appendString: @" > "];
			if ([self inspectExpression: [predicate rightExpression] code: code arguments: arguments] == NO) return NO;
			return YES;
		} else if ([predicate predicateOperatorType] == NSGreaterThanOrEqualToPredicateOperatorType
				   && [predicate comparisonPredicateModifier] == NSDirectPredicateModifier
				   && [predicate options] == 0) {
			if ([self inspectExpression: [predicate leftExpression] code: code arguments: arguments] == NO) return NO;
			[code appendString: @" >= "];
			if ([self inspectExpression: [predicate rightExpression] code: code arguments: arguments] == NO) return NO;
			return YES; */
		} else NSLog(@"Unknown operator type");
	}
	return nil;
}

- (void)dealloc {
	[query release];
	[super dealloc];
}

@end
